﻿using System.Collections.Specialized;

namespace KlearTweet.Client.Tab
{
    public partial class TabContent
    {
        private double _entityTop;
        private double _sizeDiff;
        private Model.IEntity _firstVisibleEntity;
        private Model.EntityCollection _entitySource;

        public Model.EntityCollection EntitySource
        {
            get { return _entitySource; }
            set
            {
                if (_entitySource == value)
                    return;
                if (_entitySource != null)
                    _entitySource.CollectionChanged -= OnEntitySourceChanged;

                _entitySource = value;
                _entitySource.CollectionChanged += OnEntitySourceChanged;
                OnEntitySourceChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); // Force a refresh
            }
        }

        public TabContent()
        {
            InitializeComponent();

            ListView.ItemsHost.Milliseconds = 0.5; // TODO: Remove?
            ListView.ItemsHost.Randomness = 0;
            ListView.ItemsHost.SizeChanged += OnItemsHostSizeChanged;
        }


        private void OnEntitySourceChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            Infrastructure.ThreadPoolHelper.RunOnMainThread(()
                => UpdateListViewSource(e.Action == NotifyCollectionChangedAction.Reset));
        }

        private void UpdateListViewSource(bool reset)
        {
            if (!reset && _entitySource.Count > 0)
            {
                // Keep this to move the VerticalOffset after the update is completed (so that the user can keep reading where he was)
                _firstVisibleEntity = ListView.GetFirstVisibleEntity();

                // if this entity was removed, take another just before this one
                while (_firstVisibleEntity != null && !_entitySource.Contains(_firstVisibleEntity))
                    _firstVisibleEntity = ListView.GetEntityBefore(_firstVisibleEntity);

                if (_firstVisibleEntity != null)
                {
                    var firstVisibleEntityRect = ListView.GetLocationByEntity(_firstVisibleEntity);
                    _entityTop = firstVisibleEntityRect.Top;
                    // Now, we wait for the size to change
                }
                else // All entities above the first were removed
                    ListView.ScrollToVerticalTop();
            }
            else // New/empty list
                ListView.ScrollToVerticalTop();

            ListView.SetSource(_entitySource);
        }

        private void OnItemsHostSizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
        {
            if (_firstVisibleEntity != null)
            {
                _sizeDiff = e.NewSize.Height - e.PreviousSize.Height;
                // Now, we wait for the location of this entity to change (if it doesn't, then we don't change the VerticalOffset)
                Infrastructure.ThreadPoolHelper.RunWhen(1000, LocationChanged, UpdateVerticalOffset);
            }
        }

        private bool LocationChanged()
        {
            if (_firstVisibleEntity == null)
                return true; // Stop waiting
            var firstVisibleEntityNewRect = ListView.GetLocationByEntity(_firstVisibleEntity);
            return firstVisibleEntityNewRect.Top != _entityTop; // Stop waiting when it changes
        }

        private void UpdateVerticalOffset(bool timeout)
        {
            if (_firstVisibleEntity == null)
                return; // Nothing to do

            if (!timeout)
                ListView.ElementScrollViewer.ScrollToVerticalOffset(
                    ListView.ElementScrollViewer.VerticalOffset + _sizeDiff);

            // We are done
            _firstVisibleEntity = null;
            _sizeDiff = 0;
        }
    }
}